// 这个题要注意，虽然是基类指针，但是绑定的是派生类的对象，虽然只可以访问基类部分的成员，但是这基类部分的成员也是属于派生类的，不要被迷惑了

// (a)：调用MI的print()函数

// (b)：调用MI的print()函数

// (c)：调用MI的print()函数

// 如果我们可能会删除一个指向派生类的基类指针时，应该把析构函数声明为虚函数。
// 事实上，《Effective C++》中的观点是，只要一个类有可能会被其它类所继承，
// 就应该声明虚析构函数。

// 虚函数依赖虚函数表进行工作。如果一个类中，有函数被关键词virtual进行修饰，
// 那么一个虚函数表就会被构建起来保存这个类中虚函数的地址。同时，
// 编译器会为这个类添加一个隐藏指针指向虚函数表。如果在派生类中没有重写虚函数，
// 那么，派生类中虚表存储的是父类虚函数的地址。每当虚函数被调用时，
// 虚表会决定具体去调用哪个函数。因此，C++中的动态绑定是通过虚函数表机制进行的。

// 当我们用基类指针指向派生类时，虚表指针vptr指向派生类的虚函数表。
// 这个机制可以保证派生类中的虚函数被调用到。

// (d)：调用MI的析构函数，再调用Base2的析构函数

// (e)：调用MI的析构函数，再调用D2的析构函数，再调用Base2的析构函数，再调用D1的析构函数，再调用Base1的析构函数

// (f)：调用MI的析构函数，再调用D2的析构函数，再调用Base2的析构函数，再调用D1的析构函数，再调用Base的1析构函数
/***************************************************************************
 *  @file       main.cpp
 *  @author     MISAYAONE
 *  @date       20  March 2017
 *  @remark     20  March 2017
 ***************************************************************************/

#include <iostream>
#include <list>
#include <string>
#include <vector>
using namespace std;
class B1 {
 public:
  B1() { cout << "B1 constructor" << endl; }
  virtual void print() { cout << "B1" << endl; }
  virtual ~B1() { cout << "B1 destructor" << endl; }
};
class D1 : public B1 {
 public:
  D1() { cout << "D1 constructor" << endl; }
  void print() { cout << "D1" << endl; }
  ~D1() { cout << "D1 destructor" << endl; }
};
class B2 {
 public:
  B2() { cout << "B2 constructor" << endl; }
  virtual void print() { cout << "B2" << endl; }
  virtual ~B2() { cout << "B2 destructor" << endl; }
};
class D2 : public B2 {
 public:
  D2() { cout << "D2 constructor" << endl; }
  void print() { cout << "D2" << endl; }
  ~D2() { cout << "D2 destructor" << endl; }
};
class MI : public D1, public D2 {
 public:
  MI() { cout << "MI constructor" << endl; }
  void print() { cout << "MI" << endl; }
  ~MI() { cout << "MI destructor" << endl; }
};
int main(int argc, char **argv) {
  B1 *b1 = new MI;  //构造函数的调用是从基类开始到派生类
  B2 *b2 = new MI;
  D1 *d1 = new MI;
  D2 *d2 = new MI;

  b1->print();
  b2->print();
  d1->print();
  d2->print();

  delete b1;  //删除指向派生类的基类指针需要注意其过程
  delete b2;
  delete d1;
  delete d2;

  cin.get();
  return 0;
}